package org.budo.phone.freeswitch;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.budo.graph.annotation.SpringGraph;
import org.budo.phone.api.AbstractPhoneEventFilter;
import org.budo.phone.api.BudoPhoneEvent.Type;
import org.budo.phone.freeswitch.util.PhoneEventUtil;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.mvcs.Mvcs;
import org.freeswitch.esl.client.transport.event.EslEvent;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import com.alibaba.fastjson.JSON;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author limingwei
 */
@Slf4j
@Getter
@Setter
public class FreeswitchPhoneEventFilter extends AbstractPhoneEventFilter implements InitializingBean, DisposableBean {
    private List<FreeswitchEslClient> freeswitchEslClients = new ArrayList<FreeswitchEslClient>();

    @SpringGraph
    @Override
    public void doFilter(ServletRequest request, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        try {
            this.doFilterInternal(request, servletResponse, chain);
        } catch (Throwable e) {
            log.error("#52 e=" + e + ", request=" + request, e);
            throw new RuntimeException(e);
        }
    }

    private void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        String requestURI = request.getRequestURI();

        // dialplan 请求
        if (StringUtil.endWithIgnoreCase(requestURI, "dialplan")) {
            this.handleDialplan(request, response);
            return;
        }

        // 用户认证
        if (StringUtil.endWithIgnoreCase(requestURI, "curl")) {
            this.handleCurl(request, response);
            return;
        }

        // 来自 lua
        if (StringUtil.contains(requestURI, "ivr/startservice")) {
            this.handleStartService_0(request, response);
            return;
        }

        // 来自 lua ,打断
        if (StringUtil.contains(requestURI, "ivr/breakservice")) {
            this.handleBreakService(request, response);
            return;
        }

        // 按键
        if (StringUtil.contains(requestURI, "ivr/dtmfreport")) {
            this.handleDtmfReport(request, response);
            return;
        }

        // aleg挂断
        if (StringUtil.contains(requestURI, "ivr/public_aleg_hangup")) {
            this.handlePublicALegHangup(request, response);
            return;
        }

        // 其他请求
        super.doFilter(request, response, chain);
    }

    /**
     * 呼入或群呼接通时回调
     */
    private void handleStartService_0(HttpServletRequest request, HttpServletResponse response) {
        String userdata = request.getHeader("userdata");
        if (null != userdata && !userdata.trim().isEmpty() && !"null".equalsIgnoreCase(userdata.trim())) {
            this.handleEstablishService(request, response); // 群呼
            return;
        }

        // 线路销售外呼
        // 呼入
        this.handleStartService(request, response);
    }

    /**
     * handleCurl
     */
    public void handleCurl(HttpServletRequest request, HttpServletResponse response) {
        String section = request.getParameter("section");

        if ("directory".equals(section)) {
            this.handleCurlDirectory(request, response);
            return;
        }

        log.warn("#83 handleCurl, section=" + section + ", request=" + request + ", parameterMap=" + JSON.toJSONString(Mvcs.getRequestParameterMap(request)) + ", response=" + response);
    }

    public void handlePublicALegHangup(HttpServletRequest request, HttpServletResponse response) {
        throw new RuntimeException();
    }

    public void handleEstablishService(HttpServletRequest request, HttpServletResponse response) {
        throw new RuntimeException();
    }

    public void handleBreakService(HttpServletRequest request, HttpServletResponse response) {
        throw new RuntimeException();
    }

    public void handleDtmfReport(HttpServletRequest request, HttpServletResponse response) {
        throw new RuntimeException();
    }

    public void handleStartService(HttpServletRequest request, HttpServletResponse response) {
        throw new RuntimeException();
    }

    /**
     * 默认实现，替换
     */
    public void handleDialplan(HttpServletRequest request, HttpServletResponse response) {
        throw new RuntimeException();
    }

    /**
     * 默认密码 1234
     */
    public void handleCurlDirectory(HttpServletRequest request, HttpServletResponse response) {
        throw new RuntimeException();
    }

    /**
     * 启动 esl Client
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        this.assertEslClientInited();
    }

    /**
     * @see DisposableBean
     */
    @Override
    public void destroy() {
        super.destroy();

        for (FreeswitchEslClient client : this.getFreeswitchEslClients()) {
            client.close();
        }
    }

    /**
     * 启动时尝试连接一次，以后每次请求进来都会检查是否已经连接
     *
     * @see com.taojin.freeswitch.logic.event.TaojinFreeswitchPhoneEventFilter#initEslClient()
     */
    protected void assertEslClientInited() {
        for (FreeswitchEslClient client : this.getFreeswitchEslClients()) {
            client.assertInited();
        }
    }

    protected Type eventType(EslEvent event) {
        return PhoneEventUtil.eventType(event);
    }

    protected FreeswitchPhoneEvent phoneEvent(EslEvent eslEvent, Type eventType) {
        return PhoneEventUtil.phoneEvent(eslEvent, eventType);
    }

    protected String findCallIdByUUID(String uuid) {
        for (FreeswitchEslClient eslClient : this.getFreeswitchEslClients()) {
            if (null == eslClient || !eslClient.canSend()) {
                continue;
            }

            String callId = eslClient.findCallIdByUUID(uuid);
            if (StringUtil.isNotBlank(callId)) {
                return PhoneEventUtil.uuidToCallId(callId);
            }
        }

        return null;
    }
}